package com.pucong.gitee.database.backup.business.service.util.fileService.pool;

import com.pucong.gitee.database.backup.configuration.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;

import java.io.IOException;
import java.util.concurrent.LinkedBlockingQueue;

@Slf4j
public class FtpClientWapper {

    private static final int DEFAULT_BUFFER_SIZE = 4096;

    // 连接超时时间(3分钟未使用中断)
    public static final long CONN_TIMEOUT = 3 * 60 * 1000L;

    // 存放连接包装对象的池子的引用
    private LinkedBlockingQueue<FtpClientWapper> pool;

    private FTPClient ftpClient;

    private String host;

    ///激活时间（用于判断该连接是否长时间未使用）
    private long activeTime;

    private int port;

    private String username;

    private String password;

    private boolean passiveMode;

    private String encoding;

    private int clientTimeout;

    private int transferFileType;

    public FtpClientWapper(LinkedBlockingQueue<FtpClientWapper> pool,String host, int port, String username, String password) {
        this.pool = pool;
        this.host = host;
        this.port = port;
        this.username = username;
        this.password = password;
        this.passiveMode = true;
        this.encoding = "UTF-8";
        this.clientTimeout = 10;
        this.transferFileType = FTP.BINARY_FILE_TYPE;
        this.activeTime = System.currentTimeMillis();
        this.makeObject();
    }

    public FtpClientWapper(LinkedBlockingQueue<FtpClientWapper> pool,String host, int port, String username, String password, boolean passiveMode, String encoding, int clientTimeout, int transferFileType) {
        this.pool = pool;
        this.host = host;
        this.port = port;
        this.username = username;
        this.password = password;
        this.passiveMode = passiveMode;
        this.encoding = encoding;
        this.clientTimeout = clientTimeout;
        this.transferFileType = transferFileType;
        this.activeTime = System.currentTimeMillis();
        this.makeObject();
    }

    private void makeObject() {
        FTPClient ftpClient = new FTPClient();
        ftpClient.setConnectTimeout(clientTimeout);
        try {
            ftpClient.connect(host, port);
            int reply = ftpClient.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftpClient.disconnect();
                log.warn("FTPServer refused connection");
                throw new BusinessException("FTP服务器拒绝连接");
            }
            boolean result = ftpClient.login(username, password);
            if (!result) {
                throw new BusinessException("ftpClient登陆失败! userName:" + username + " ; password:" + password);
            }
            ftpClient.setFileType(transferFileType);
            ftpClient.setBufferSize(DEFAULT_BUFFER_SIZE);
            ftpClient.setControlEncoding(encoding);
            if (passiveMode) {
                ftpClient.enterLocalPassiveMode();
            }
        } catch (IOException e) {
            log.error("FTP服务器创建连接失败",e);
            throw new BusinessException("FTP服务器创建连接失败");
        }
         this.ftpClient = ftpClient;
    }

    public void destroyObject() {
        try {
            if (ftpClient != null && ftpClient.isConnected()) {
                ftpClient.logout();
            }
        } catch (IOException e) {
            log.error("FTP服务器关闭连接失败",e);
            throw new BusinessException("FTP服务器关闭连接失败");
        } finally {
            try {
                ftpClient.disconnect();
            } catch (IOException io) {
                log.error("FTP服务器关闭连接失败",io);
                throw new BusinessException("FTP服务器关闭连接失败");
            }
        }
    }

    public boolean validateObject() {
        try {
            return ftpClient.sendNoOp();
        } catch (IOException e) {
            throw new RuntimeException("Failed to validate client: ", e);
        }
    }

    public FTPClient getFtpClient(){
        this.activeTime = System.currentTimeMillis();
        return ftpClient;
    }

    public void close(){
        log.info("-------------------------------------开始执行连接回收操作-------------------------------------");
        this.activeTime = System.currentTimeMillis();
        final boolean add = pool.add(this);
        log.info("-------------------------------------连接回收完毕-------------------------------------");
    }

    /**
     * 检测连接是否超时
     *
     * @return
     */
    public boolean checkTimeOut() {
        if ((System.currentTimeMillis() - this.activeTime) > FtpClientWapper.CONN_TIMEOUT) {
            return true;
        }
        return false;
    }
}
